From 1f3f933edf06ddc7dcb8e474fd845c99d8be01f9 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 6 Nov 2014 12:21:28 +0100 Subject: [PATCH] GdkX11GLContext: Use bitblit for swap if no buffer age support If buffer age is undefined and the updated area is not the whole window then we use bit-blits instead of swap-buffers to end the frame. This allows us to not repaint the entire window unnecessarily if buffer_age is not supported, like e.g. with DRI2. --- gdk/gdkglcontext.c | 10 ++++++++ gdk/gdkglcontextprivate.h | 1 + gdk/gdkwindow.c | 3 --- gdk/x11/gdkglcontext-x11.c | 48 ++++++++++++++++++++++++++++++++++++-- gdk/x11/gdkglcontext-x11.h | 1 + 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index b03c82b19c..e1b8f98e78 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -87,6 +87,7 @@ typedef struct { guint realized : 1; guint use_texture_rectangle : 1; guint has_gl_framebuffer_blit : 1; + guint has_frame_terminator : 1; GdkGLContextPaintData *paint_data; } GdkGLContextPrivate; @@ -359,6 +360,14 @@ gdk_gl_context_has_framebuffer_blit (GdkGLContext *context) return priv->has_gl_framebuffer_blit; } +gboolean +gdk_gl_context_has_frame_terminator (GdkGLContext *context) +{ + GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); + + return priv->has_frame_terminator; +} + static void gdk_gl_context_realize (GdkGLContext *context) { @@ -369,6 +378,7 @@ gdk_gl_context_realize (GdkGLContext *context) has_texture_rectangle = epoxy_has_gl_extension ("GL_ARB_texture_rectangle"); priv->has_gl_framebuffer_blit = epoxy_has_gl_extension ("GL_EXT_framebuffer_blit"); + priv->has_frame_terminator = epoxy_has_gl_extension ("GL_GREMEDY_frame_terminator"); if (_gdk_gl_flags & GDK_GL_FLAGS_TEXTURE_RECTANGLE) priv->use_texture_rectangle = TRUE; diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h index 8a88242696..31f4a64785 100644 --- a/gdk/gdkglcontextprivate.h +++ b/gdk/gdkglcontextprivate.h @@ -68,6 +68,7 @@ typedef struct { GdkGLContextPaintData *gdk_gl_context_get_paint_data (GdkGLContext *context); gboolean gdk_gl_context_use_texture_rectangle (GdkGLContext *context); gboolean gdk_gl_context_has_framebuffer_blit (GdkGLContext *context); +gboolean gdk_gl_context_has_frame_terminator (GdkGLContext *context); void gdk_gl_context_end_frame (GdkGLContext *context, cairo_region_t *painted, cairo_region_t *damage); diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index bc9856975b..5970ee38e7 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -3108,9 +3108,6 @@ gdk_window_end_paint (GdkWindow *window) gdk_gl_context_end_frame (window->gl_paint_context, window->current_paint.region, window->active_update_area); - - if (epoxy_has_gl_extension ("GL_GREMEDY_frame_terminator")) - glFrameTerminatorGREMEDY(); } else { diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c index fe1b18ad3c..b545f28c7d 100644 --- a/gdk/x11/gdkglcontext-x11.c +++ b/gdk/x11/gdkglcontext-x11.c @@ -157,6 +157,8 @@ gdk_x11_window_invalidate_for_new_frame (GdkWindow *window, buffer_age = 0; + context_x11->do_blit_swap = FALSE; + if (display_x11->has_glx_buffer_age) { gdk_gl_context_make_current (window->gl_paint_context); @@ -164,9 +166,20 @@ gdk_x11_window_invalidate_for_new_frame (GdkWindow *window, GLX_BACK_BUFFER_AGE_EXT, &buffer_age); } + invalidate_all = FALSE; if (buffer_age == 0 || buffer_age >= 4) - invalidate_all = TRUE; + { + cairo_rectangle_int_t whole_window = { 0, 0, gdk_window_get_width (window), gdk_window_get_height (window) }; + + if (gdk_gl_context_has_framebuffer_blit (window->gl_paint_context) && + cairo_region_contains_rectangle (update_area, &whole_window) != CAIRO_REGION_OVERLAP_IN) + { + context_x11->do_blit_swap = TRUE; + } + else + invalidate_all = TRUE; + } else { if (buffer_age >= 2) @@ -199,6 +212,25 @@ gdk_x11_window_invalidate_for_new_frame (GdkWindow *window, } +static void +gdk_gl_blit_region (GdkWindow *window, cairo_region_t *region) +{ + int n_rects, i; + int scale = gdk_window_get_scale_factor (window); + int wh = gdk_window_get_height (window); + cairo_rectangle_int_t rect; + + n_rects = cairo_region_num_rectangles (region); + for (i = 0; i < n_rects; i++) + { + cairo_region_get_rectangle (region, i, &rect); + glScissor (rect.x * scale, (wh - rect.y - rect.height) * scale, rect.width * scale, rect.height * scale); + glBlitFramebuffer (rect.x * scale, (wh - rect.y - rect.height) * scale, (rect.x + rect.width) * scale, (wh - rect.y) * scale, + rect.x * scale, (wh - rect.y - rect.height) * scale, (rect.x + rect.width) * scale, (wh - rect.y) * scale, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + } +} + static void gdk_x11_gl_context_end_frame (GdkGLContext *context, cairo_region_t *painted, @@ -257,7 +289,19 @@ gdk_x11_gl_context_end_frame (GdkGLContext *context, } } - glXSwapBuffers (dpy, drawable); + if (context_x11->do_blit_swap) + { + glDrawBuffer(GL_FRONT); + glReadBuffer(GL_BACK); + gdk_gl_blit_region (window, painted); + glDrawBuffer(GL_BACK); + glFlush(); + + if (gdk_gl_context_has_frame_terminator (context)) + glFrameTerminatorGREMEDY (); + } + else + glXSwapBuffers (dpy, drawable); if (context_x11->do_frame_sync && info != NULL && display_x11->has_glx_video_sync) glXGetVideoSyncSGI (&info->last_frame_counter); diff --git a/gdk/x11/gdkglcontext-x11.h b/gdk/x11/gdkglcontext-x11.h index 865a7654a7..957125044d 100644 --- a/gdk/x11/gdkglcontext-x11.h +++ b/gdk/x11/gdkglcontext-x11.h @@ -49,6 +49,7 @@ struct _GdkX11GLContext guint is_direct : 1; guint do_frame_sync : 1; + guint do_blit_swap : 1; }; struct _GdkX11GLContextClass -- 2.30.2